package bll

import (
	"context"
	"fmt"
	"shadow/lib/cache"
	OurJson "shadow/lib/ourjson"
	"shadow/store/redis"
	"time"
)

// storage 存储
type storage struct {
	cache.SyncCache
}

// NewStorage returns a new storage.
func NewStorage() *storage {
	return &storage{}
}

// IsExistCache returns true if the device exists.
func (s *storage) IsExistCache(deviceName string) bool {
	_, ok := s.SyncCache.Get(deviceName)
	return ok
}

// Put puts the device into the cache.
func (s *storage) Put(stateType StateType, deviceName, metaType, key string, value interface{}) error {
	// Todo: 查看缓存中是否存在
	lock := redis.TRedLock{}
	conn := redis.KV.GetRedisPool().Get()
	lock.Lock(conn, deviceName, 10)
	defer lock.UnLock(conn)

	srcJson := ``
	if !s.IsExistCache(deviceName) {
		if err := redis.KV.GetValue(context.Background(), DeviceShadow, deviceName, &srcJson); err != nil && err.Error() != "key not exist" {
			return err
		}

		// 默认数据
		if srcJson == `` {
			srcJson = s.defaultJson()
		}

	} else {
		v, ok := s.Get(deviceName)
		if !ok {
			return nil
		}

		srcJson = v.(string)
	}

	// 构建json
	newJson, err := s.buildJson(stateType, srcJson, metaType, key, value)
	if err != nil {
		return err
	}

	// 存储数据
	if err = redis.KV.AddValueWithExpireTime(context.Background(), DeviceShadow, deviceName, newJson, time.Hour*15*24); err != nil {
		return err
	}

	// 更新缓存
	s.SyncCache.Del(deviceName)
	return nil
}

// GetShadowValue 获取影子数据
func (s *storage) GetShadowValue(stateType StateType, deviceName, metaType, key string) (interface{}, error) {
	shadowData, err := s.GetShadow(deviceName)
	if err != nil {
		return nil, err
	}

	// 解析json
	jsonObject, err := OurJson.ParseObject(shadowData)
	if err != nil {
		return nil, err
	}

	// 获取reported
	jsonObject = jsonObject.GetJsonObject(MetaTypeState).GetJsonObject(string(stateType))
	if !jsonObject.HasKey(metaType) {
		return nil, fmt.Errorf("metaType not exist")
	}

	// 获取reported
	value, err := jsonObject.GetJsonObject(metaType).Get(key)
	if err != nil {
		return nil, err
	}
	return value.Interface(), nil
}

// GetStateShadow 获取影子数据
func (s *storage) GetStateShadow(stateType StateType, deviceName string) (interface{}, error) {
	shadowData, err := s.GetShadow(deviceName)
	if err != nil {
		return nil, err
	}

	// 解析json
	jsonObject, err := OurJson.ParseObject(shadowData)
	if err != nil {
		return nil, err
	}

	// 获取reported
	value, err := jsonObject.GetJsonObject(MetaTypeState).Get(string(stateType))
	if err != nil {
		return nil, err
	}
	return value.Interface(), nil
}

// GetMetaTypeShadow 获取影子数据
func (s *storage) GetMetaTypeShadow(stateType StateType, deviceName, metaType string) (interface{}, error) {
	shadowData, err := s.GetShadow(deviceName)
	if err != nil {
		return nil, err
	}

	// 解析json
	jsonObject, err := OurJson.ParseObject(shadowData)
	if err != nil {
		return nil, err
	}

	// 获取reported
	jsonObject = jsonObject.GetJsonObject(MetaTypeState).GetJsonObject(string(stateType))
	if !jsonObject.HasKey(metaType) {
		return nil, fmt.Errorf("metaType not exist")
	}

	// 获取reported
	value, err := jsonObject.Get(metaType)
	if err != nil {
		return nil, err
	}
	return value.Interface(), nil
}

// GetShadow 获取影子
func (s *storage) GetShadow(deviceName string) (shadow string, err error) {
	// Todo: 查看缓存中是否存在
	if s.IsExistCache(deviceName) {
		data, _ := s.Get(deviceName)
		return data.(string), nil
	}

	// Todo: 查看redis中是否存在
	if err = redis.KV.GetValue(context.Background(), DeviceShadow, deviceName, &shadow); err == nil && shadow != "" {
		s.SyncCache.Set(deviceName, shadow, time.Second*60)
		return
	}

	// Todo: 查看数据库中是否存在
	return
}

// buildJson 构建json字符串
func (s *storage) buildJson(stateType StateType, srcJson string, metaType, key string, value interface{}) (newJson string, err error) {
	// 解析json
	jsonObject, err := OurJson.ParseObject(srcJson)
	if err != nil {
		return "", err
	}

	// 获取reported
	object := jsonObject.GetJsonObject(MetaTypeState).GetJsonObject(string(stateType)).GetJsonObject(metaType)
	object.Put(key, value)
	// 转换为字符串
	data, err := jsonObject.MarsharJSON()
	return string(data), err
}

// defaultJson 默认的json字符串
func (s *storage) defaultJson() string {
	return `{
		"state": {
			"desired": {
				"attribute": {},
				"status": {},
				"feature_set":{}
			},
			"reported": {
				"attribute": {},
				"status": {},
				"feature_set":{}
			}
		},
		"metadata": {
			"desired": {
				"attribute": {},
				"status": {},
				"feature_set":{}
			},
			"reported": {
				"attribute": {},
				"status": {},
				"feature_set":{}
			}
		},
		"timestamp": 0,
		"version": 1
	}`
}
